#ifndef XGSIGNAL_H
#define XGSIGNAL_H

class NullClass;

template<typename P1 = NullClass>
class XgSignal;

#define signal( ... ) XgSignal< __VA_ARGS__ >

#include "Templates/XgSlot.h"
#include "XgMemberSlot.h"
#include "XgFunctionSlot.h"
#include "XgAsyncSlot.h"
#include "XgMessagesProcessor.h"
#include "XgExceptions.h"
#include "XgSignalBase.h"
#include <vector>

/************************************************************************/
/* Class XgSignal (params:1) Basic Template                             */
/************************************************************************/
template<typename P1 /*= NullClass*/>
class XgSignal : public XgSignalBase
{
public:
	typedef std::vector< XgSlot<P1>* > Connections;

public:
	XgSignal(){}
	~XgSignal(){}

private:
	void connect( XgSlot<P1>* slot )
	{
		_connections.push_back(slot);
	}

public:
	template<class Cs, class Cm>
	void connect( Cs* subject, void (Cm::*method)(P1) )
	{
		connect( new XgMemberSlot<Cm, P1>(subject, method) );
	}

	void connect( void (*function)(P1) )
	{
		connect( new XgFunctionSlot<P1>(function) );
	}

	template<class Cs, class Cm>
	void connect( Cs* subject, void (Cm::*method)(P1), XgMessagesProcessor* dstProcessor )
	{
		connect( new XgAsyncSlot<P1>( new XgMemberSlot<Cm, P1>(subject, method), dstProcessor ) );
	}

	void emit(P1 a)
	{
		Connections::iterator iter;
		for( iter = _connections.begin(); iter != _connections.end(); iter++ )
		{
			(*iter)->invoke(a);
		}
		set();
	}

private:
	Connections _connections;
};

/************************************************************************/
/* Class XgSignal (params:0)                                            */
/************************************************************************/
template<>
class XgSignal<NullClass> : public XgSignalBase
{
public:
	typedef std::vector< XgSlot<>* > Connections;
public:
	XgSignal(){}
	~XgSignal(){}
public:
	void connect( XgSlot<>* slot )
	{
		_connections.push_back(slot);
	}
public:
	template<class Cs, class Cm>
	void connect( Cs* subject, void (Cm::*method)() )
	{
		connect( new XgMemberSlot<Cm>(subject, method) );
	}

	void connect( void (*function)() )
	{
		connect( new XgFunctionSlot<>(function) );
	}

	template<class Cs, class Cm>
	void connect( Cs* subject, void (Cm::*method)(), XgMessagesProcessor* dstProcessor )
	{
		connect( new XgAsyncSlot<>( new XgMemberSlot<Cm>(subject, method), dstProcessor ) );
	}

	void emit()
	{
		Connections::iterator iter;
		for( iter = _connections.begin(); iter != _connections.end(); iter++ )
		{
			(*iter)->invoke();
		}
		set();
	}
private:
	Connections _connections;
};

#endif //XGSIGNAL_H
